import re
import json
import random
from pathlib import Path
from typing import Dict, List, Callable, Tuple, Optional


class RegExpGenerator:
    # 通用无效用例模板
    COMMON_INVALID_TEMPLATES = [
        ("", "空输入"),
        ("X" * 51, "超长字符串"),
        ("NULL", "NULL输入"),
        ("!@#$%^&*()", "特殊字符"),
        ("中文测试", "中文字符")
    ]
    
    # 字符替换规则
    CORRUPTIONS = {
        'letter': 'A',
        'chinese': '中',
        'symbol': '@',
        'space': ' ',
        'overflow': '1'
    }

    def __init__(self, json_path: str = None):
        """
        初始化正则表达式生成器
        :param json_path: 可选的自定义JSON路径
        """
        default_path = Path(__file__).parent.parent.parent / "tests" / "test_data" / "professional_patterns.json"
        with open(json_path or default_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
            self.patterns = {
                # 简单模式
                'LCMP - ^L\\d{5}$': data["Listed Chinese Medicine Practitioner"],
                'LRCMP - LR\\d{4}$': data["Chinese Medicine Practitioner with Limited Registration"],
                'RCMP - ^\\d{6}$': data["Registered Chinese Medicine Practitioner"],
                'RPH - ^P\\d{5}$': data["Pharmacists"],
                'CPR - ^CC\\d{6}$': data["Chiropractor"],
                'DHT - ^DH\\d{4}$': data["Dental Hygienists"],
                'ROP - OP1\\d{5}$': data["Optometrists"],
                
                # 复杂模式
                'RMT - ^MT[1-3]\\d{5}$': data["Medical Laboratory Technologists"],
                'ROT - ^(OT[1-2]\\d{5}|NA)$': data["Occupational Therapist"],
                'RPT - ^(PT[1-2]\\d{5}|NA)$': data["Physiotherapist"],
                'RRD - ^(RD[1-4]\\d{5}|RT[1-2]\\d{5}|NA)$': data["Radiographers"],
                
                'RDT - ^D[LSTP]?\\d{5}$': data["Dentist"],
                'RMP - ^M[LPS]?\\d{5}$': data["Doctor"],
                'RNU': r"^RN(C\d|S\d|P\d|G\d|GF|GM|LG|SG|TG|LP|SP|TP)\d{6}$",
                'ENU': r"^EN(G\d|P\d|LG|SG|TG|LP|SP|TP)\d{6}$"
            }
        
        self.handlers = self._init_handlers()
        self._pattern_cache = {}

    def _init_handlers(self) -> Dict[str, Dict[str, Callable]]:
        """初始化处理器配置"""
        return {
            'default': {
                'valid': self._generate_valid_cases,
                'invalid': lambda p: [
                    *self._generate_prefix_errors(p),
                    *self._generate_digit_violations(p)
                ]
            },
            'no_prefix': {
                'valid': self._generate_valid_cases,
                'invalid': self._generate_digit_violations
            },
            'complex': {
                'valid': self._generate_valid_cases,
                'invalid': lambda p: self._handle_pattern(p)['invalid']
            }
        }

    def generate_all_cases(self) -> Dict[str, Dict[str, List[Dict]]]:
        """为所有模式生成测试用例"""
        return {
            name: self.generate_cases(pattern)
            for name, pattern in self.patterns.items()
        }
    
    def generate_cases(self, pattern: str) -> Dict[str, List[Dict]]:
        """为单个模式生成用例"""
        if pattern in self._pattern_cache:
            return self._pattern_cache[pattern]
            
        cases = self._handle_pattern(pattern)
        
        # 添加通用无效用例
        prefix = self._get_base_prefix(pattern)
        cases['invalid'].extend([
            {'value': v, 'description': f"通用: {d}", 'type': 'common'}
            for v, d in self.COMMON_INVALID_TEMPLATES
            if not (prefix == "NA" and v)  # 跳过NA模式的通用无效用例
        ])
        
        self._pattern_cache[pattern] = cases
        return cases
    
    def _handle_pattern(self, pattern: str) -> Dict[str, List[Dict]]:
        """统一处理各种模式"""
        if self._is_nurse_pattern(pattern):
            return self._generate_nurse_cases(pattern)
        elif "|" in pattern:  # 多选项模式
            return self._handle_multi_option_pattern(pattern)
        elif "[" in pattern or "(" in pattern:  # 可选字母或分组
            return self._handle_complex_single_pattern(pattern)
        else:
            handler = self._select_handler(pattern)
            return {
                'valid': handler['valid'](pattern),
                'invalid': handler['invalid'](pattern)
            }

    def _is_nurse_pattern(self, pattern: str) -> bool:
        """判断是否为护士模式"""
        return pattern in [
            r"^RN(C\d|S\d|P\d|G\d|GF|GM|LG|SG|TG|LP|SP|TP)\d{6}$",
            r"^EN(G\d|P\d|LG|SG|TG|LP|SP|TP)\d{6}$"
        ]

    def _generate_nurse_cases(self, pattern: str) -> Dict[str, List[Dict]]:
        """生成护士相关测试用例（统一处理RN和EN前缀的不同组合类型）"""
        if pattern.startswith("^RN"):
            prefix = "RN"
            # RN前缀的组合规则：
            # 单字母组合（C/S/P/G）数字长度为7
            # 双字母组合数字长度为6
            combos = [
                (["C", "S", "P", "G"], 7),      # 单字母组合
                (["GF", "GM", "LG", "SG", "TG", "LP", "SP", "TP"], 6)  # 双字母组合
            ]
        else:
            prefix = "EN"
            # EN前缀的组合规则：
            # 单字母组合（G/P）数字长度为7 
            # 双字母组合数字长度为6
            combos = [
                (["G", "P"], 7),                 # 单字母组合
                (["LG", "SG", "TG", "LP", "SP", "TP"], 6)  # 双字母组合
            ]
        
        # 分别生成不同组合类型的用例
        all_valid = []
        all_invalid = []
        for valid_combinations, digit_len in combos:
            cases = self._generate_standard_cases(
                prefix=prefix,
                valid_combinations=valid_combinations,
                digit_len=digit_len,
                pattern_type="optional"
            )
            all_valid.extend(cases["valid"])
            all_invalid.extend(cases["invalid"])
        
        return {
            "valid": all_valid,
            "invalid": all_invalid
        }

    def _generate_standard_cases(
        self,
        prefix: str,
        valid_combinations: List[str],
        digit_len: int,
        pattern_type: str = "standard"
    ) -> Dict[str, List[Dict]]:
        """
        标准用例生成方法
        :param prefix: 基础前缀
        :param valid_combinations: 有效组合列表
        :param digit_len: 数字长度
        :param pattern_type: 模式类型(standard/optional/range)
        """
        cases = {"valid": [], "invalid": []}
        
        # 生成有效用例
        for combo in valid_combinations:
            full_prefix = prefix + combo
            cases["valid"].extend([
                {"value": f"{full_prefix}{'0'*digit_len}", "description": f"有效: {full_prefix} (边界:0)"},
                {"value": f"{full_prefix}{'9'*digit_len}", "description": f"有效: {full_prefix} (边界:9)"},
                {"value": f"{full_prefix}{self._random_digits(digit_len)}", "description": f"有效: {full_prefix}"}
            ])
        
        # 生成无效用例
        self._generate_common_invalid_cases(
            base_prefix=prefix,
            valid_options=valid_combinations,
            digit_len=digit_len,
            cases=cases,
            pattern_type=pattern_type
        )
        
        return cases

    def _handle_multi_option_pattern(self, pattern: str) -> Dict[str, List[Dict]]:
        """处理多选项模式"""
        cases = {"valid": [], "invalid": []}
        inner_pattern = pattern[1:-1]  # 去除外层^和$
        
        # 处理带括号的多选项模式
        if inner_pattern.startswith('(') and inner_pattern.endswith(')'):
            options = inner_pattern[1:-1].split("|")
        else:
            options = [inner_pattern]
        
        for option in options:
            if option == "NA":
                self._generate_na_cases(cases)
            elif self._is_range_pattern(option):
                self._handle_range_pattern(option, cases)
            else:
                sub_cases = self._handle_complex_single_pattern(f"^{option}$")
                cases["valid"].extend(sub_cases["valid"])
                cases["invalid"].extend(sub_cases["invalid"])
        
        return cases

    def _handle_complex_single_pattern(self, pattern: str) -> Dict[str, List[Dict]]:
        """处理单个复杂模式"""
        if pattern == "^D[LSTP]?\\d{5}$":
            return self._generate_standard_cases(
                prefix="D",
                valid_combinations=["", "L", "S", "T", "P"],
                digit_len=5,
                pattern_type="optional"
            )
        elif pattern == "^M[LPS]?\\d{5}$":
            return self._generate_standard_cases(
                prefix="M",
                valid_combinations=["", "L", "P", "S"],
                digit_len=5,
                pattern_type="optional"
            )
        elif pattern == "^MT[1-3]\\d{5}$":
            # 处理MT[1-3]\d{5}模式
            cases = {"valid": [], "invalid": []}
            
            # 生成有效用例
            for num in range(1, 4):  # 1-3
                base_value = f"MT{num}"
                cases["valid"].extend([
                    {"value": f"{base_value}{'0'*5}", "description": f"有效: {base_value} (边界:0)"},
                    {"value": f"{base_value}{'9'*5}", "description": f"有效: {base_value} (边界:9)"},
                    {"value": f"{base_value}{self._random_digits(5)}", "description": f"有效: {base_value}"}
                ])
            
            # 生成无效用例
            self._generate_range_invalid_cases("MT", 1, 3, 5, cases)
            return cases
        elif pattern == "^OP1\\d{5}$":
            return self._generate_standard_cases(
                prefix="OP1",
                valid_combinations=[""],
                digit_len=5,
                pattern_type="standard"
            )
        else:
            return self._generate_simple_cases(pattern)

    def _generate_simple_cases(self, pattern: str) -> Dict[str, List[Dict]]:
        """生成简单模式的测试用例"""
        base_prefix = self._get_base_prefix(pattern)
        digit_len = self._parse_digit_length(pattern)
        
        return self._generate_standard_cases(
            prefix=base_prefix,
            valid_combinations=[""],
            digit_len=digit_len,
            pattern_type="standard"
        )

    def _generate_common_invalid_cases(
        self,
        base_prefix: str,
        valid_options: List[str],
        digit_len: int,
        cases: Dict[str, List[Dict]],
        pattern_type: str
    ):
        """
        生成通用无效用例
        :param base_prefix: 基础前缀
        :param valid_options: 有效选项列表
        :param digit_len: 数字长度
        :param cases: 用例字典
        :param pattern_type: 模式类型(range/optional)
        """
        # 1. 大小写错误
        if base_prefix.isupper():
            cases["invalid"].append({
                "value": f"{base_prefix.lower()}{'1'*digit_len}",
                "description": "前缀大小写错误",
                "type": "rule"
            })

        # 2. 前缀+选项随机小写
        for opt in valid_options:
            if opt:
                # 随机选择是前缀小写还是选项小写
                if random.choice([True, False]):
                    # 前缀小写，选项保持原样
                    cases["invalid"].append({
                        "value": f"{base_prefix.lower()}{opt}{'2'*digit_len}",
                        "description": f"前缀小写错误 ({base_prefix}{opt})",
                        "type": "rule"
                    })
                else:
                    # 前缀保持原样，选项小写
                    cases["invalid"].append({
                        "value": f"{base_prefix}{opt.lower()}{'3'*digit_len}",
                        "description": f"选项小写错误 ({base_prefix}{opt})",
                        "type": "rule"
                    })
                
                # 确保至少有一个完全小写的用例
                cases["invalid"].append({
                    "value": f"{base_prefix.lower()}{opt.lower()}{'4'*digit_len}",
                    "description": f"完全小写错误 ({base_prefix}{opt})",
                    "type": "rule"
                })
        
        # 3. 非数字字符
        for desc, char in self.CORRUPTIONS.items():
            if desc not in ['overflow', 'space']:
                # 基础非法字符用例
                cases["invalid"].append({
                    "value": f"{base_prefix}{opt}{char * digit_len}",
                    "description": f"数字部分包含非法字符 ({desc})",
                    "type": "rule"
                })
                
                # 在prefix和数字之间插入非法字符
                # cases["invalid"].append({
                #     "value": f"{base_prefix}{char}{self._random_digits(digit_len)}",
                #     "description": f"前缀后包含非法字符 ({desc})",
                #     "type": "rule"
                # })
                
                # 结合valid_options生成非法组合
                for opt in valid_options:
                    if opt:
                        cases["invalid"].append({
                            "value": f"{base_prefix}{opt}{char}{self._random_digits(digit_len)}",
                            "description": f"非法组合 ({base_prefix}{opt}...) 包含非法字符 ({desc})",
                            "type": "rule"
                        })
        
        # 4. 数字长度错误
        cases["invalid"].extend([
            {
                "value": f"{base_prefix}{opt}{'2'*(digit_len-1)}",
                "description": f"数字过短 ({digit_len-1})",
                "type": "rule"
            },
            {
                "value": f"{base_prefix}{opt}{'8'*(digit_len+1)}",
                "description": f"数字过长 ({digit_len+1})",
                "type": "rule"
            }
        ])
        
        # 5. 特定模式类型的无效用例
        if pattern_type == "range" and all(opt.isdigit() for opt in valid_options if opt):
            start = min(int(opt) for opt in valid_options if opt)
            end = max(int(opt) for opt in valid_options if opt)
            if start > 1:
                cases["invalid"].append({
                    "value": f"{base_prefix}{start-1}{'0'*digit_len}",
                    "description": f"无效: {base_prefix}{start-1} 不在范围内",
                    "type": "rule"
                })
            cases["invalid"].append({
                "value": f"{base_prefix}{end+1}{'0'*digit_len}",
                "description": f"无效: {base_prefix}{end+1} 不在范围内",
                "type": "rule"
            })
        elif pattern_type == "optional":
            cases["invalid"].append({
                "value": f"{base_prefix}X{self._random_digits(digit_len)}",
                "description": "非法前缀组合",
                "type": "rule"
            })

    def _generate_na_cases(self, cases: Dict[str, List[Dict]]):
        """生成NA相关的用例"""
        cases["valid"].append({"value": "NA", "description": "有效: NA 用例"})
        cases["invalid"].extend([
            {"value": "Na", "description": "无效NA用例(大小写错误)", "type": "rule"},
            {"value": "na", "description": "无效NA用例(大小写错误)", "type": "rule"},
            {"value": "NAA", "description": "无效NA格式(多余字符)", "type": "rule"},
            {"value": "N1", "description": "无效NA格式(包含数字)", "type": "rule"},
            {"value": "N", "description": "无效NA格式(不完整)", "type": "rule"}
        ])

    def _is_range_pattern(self, pattern: str) -> bool:
        """检测是否为XX[1-2]\\d{5}这类模式"""
        return bool(re.search(r'^[A-Z]{2}\[\d-\d\]\\d\{\d+\}$', pattern))

    def _handle_range_pattern(self, pattern: str, cases: Dict[str, List[Dict]]):
        """处理XX[1-2]\d{5}这类模式"""
        try:
            # 解析模式结构
            prefix = pattern[:2]
            range_start = int(pattern[3])
            range_end = int(pattern[5])
            digit_len = int(pattern.split("{")[1].replace("}", ""))
            
            # 生成有效用例
            for num in range(range_start, range_end + 1):
                base_value = f"{prefix}{num}"
                cases["valid"].extend([
                    {"value": f"{base_value}{'0'*digit_len}", "description": f"有效: {base_value} (边界:0)"},
                    {"value": f"{base_value}{'9'*digit_len}", "description": f"有效: {base_value} (边界:9)"},
                    {"value": f"{base_value}{self._random_digits(digit_len)}", "description": f"有效: {base_value}"}
                ])
            
            # 生成无效用例
            self._generate_range_invalid_cases(prefix, range_start, range_end, digit_len, cases)
        except Exception as e:
            print(f"处理范围模式 {pattern} 时出错: {str(e)}")

    def _generate_range_invalid_cases(self, prefix: str, start: int, end: int, digit_len: int, cases: Dict[str, List[Dict]]):
        """为范围模式生成无效用例"""
        # 范围外数字
        if start > 0:
            cases["invalid"].append({
                "value": f"{prefix}{start-1}{'0'*digit_len}",
                "description": f"无效: {prefix}{start-1} 不在范围内",
                "type": "rule"
            })
        cases["invalid"].append({
            "value": f"{prefix}{end+1}{'0'*digit_len}",
            "description": f"无效: {prefix}{end+1} 不在范围内", 
            "type": "rule"
        })
        
        # 数字长度错误
        cases["invalid"].extend([
            {
                "value": f"{prefix}{start}{'2'*(digit_len-1)}",
                "description": f"数字过短 ({digit_len-1})",
                "type": "rule"
            },
            {
                "value": f"{prefix}{start}{'8'*(digit_len+1)}",
                "description": f"数字过长 ({digit_len+1})",
                "type": "rule"
            }
        ])
        
        # 大小写错误
        cases["invalid"].append({
            "value": f"{prefix.lower()}{start}{'5'*digit_len}",
            "description": "前缀大小写错误",
            "type": "rule"
        })
        
        # 非数字字符
        for desc, char in self.CORRUPTIONS.items():
            if desc not in ['overflow', 'space']:
                cases["invalid"].append({
                    "value": f"{prefix}{start}{char * digit_len}",
                    "description": f"非数字字符 ({desc})",
                    "type": "rule"
                })
                # 在数字部分插入非法字符
                cases["invalid"].append({
                    "value": f"{prefix}{start}{self._random_digits(digit_len//2)}{char}{self._random_digits(digit_len//2)}",
                    "description": f"数字部分包含非法字符 ({desc})",
                    "type": "rule"
                })

    def _select_handler(self, pattern: str) -> Dict[str, Callable]:
        """根据模式特征选择处理器"""
        if re.match(r'^\^\\d', pattern):  # 纯数字前缀
            return self.handlers['no_prefix']
        return self.handlers['default']

    def _generate_valid_cases(self, pattern: str) -> List[Dict]:
        """生成有效用例（含边界值）"""
        if self._is_complex_pattern(pattern):
            if pattern == "^D[LSTP]?\\d{5}$":
                return self._generate_standard_cases(
                    prefix="D",
                    valid_combinations=["", "L", "S", "T", "P"],
                    digit_len=5,
                    pattern_type="optional"
                )["valid"]
            elif pattern == "^M[LPS]?\\d{5}$":
                return self._generate_standard_cases(
                    prefix="M",
                    valid_combinations=["", "L", "P", "S"],
                    digit_len=5,
                    pattern_type="optional"
                )["valid"]
            elif pattern == "^MT[1-3]\\d{5}$":
                cases = []
                for num in range(1, 4):  # 1-3
                    base_value = f"MT{num}"
                    cases.extend([
                        {"value": f"{base_value}{'0'*5}", "description": f"有效: {base_value} (边界:0)"},
                        {"value": f"{base_value}{'9'*5}", "description": f"有效: {base_value} (边界:9)"},
                        {"value": f"{base_value}{self._random_digits(5)}", "description": f"有效: {base_value}"}
                    ])
                return cases
            elif pattern == "^OP1\\d{5}$":
                return self._generate_standard_cases(
                    prefix="OP1",
                    valid_combinations=[""],
                    digit_len=5,
                    pattern_type="standard"
                )["valid"]
            else:
                return []
                
        base_prefix = self._get_base_prefix(pattern)
        digit_len = self._parse_digit_length(pattern)
        
        return [
            {"value": f"{base_prefix}{'0'*digit_len}", "description": f"有效: {base_prefix} (边界:0)"},
            {"value": f"{base_prefix}{'9'*digit_len}", "description": f"有效: {base_prefix} (边界:9)"},
            {"value": f"{base_prefix}{self._random_digits(digit_len)}", "description": f"有效: {base_prefix}"}
        ]
    def _generate_prefix_errors(self, pattern: str) -> List[Dict]:
        """生成前缀相关错误用例"""
        errors = []
        prefix_match = re.match(r'^\^([A-Za-z]+)', pattern)
        
        if not prefix_match:
            return errors
        
        prefix = prefix_match.group(1)
        digit_len = self._parse_digit_length(pattern)
        
        # 大小写错误
        if prefix.isupper():
            errors.append({
                'value': f"{prefix.lower()}{'6'*digit_len}",
                'description': f"前缀大小写错误: {prefix.lower()}",
                'type': 'rule'
            })
        
        # 字母替换错误
        corrupted_prefix = re.sub(r'[A-Z]', self.CORRUPTIONS['letter'], prefix)
        if corrupted_prefix != prefix:
            errors.append({
                'value': f"{corrupted_prefix}{'1'*digit_len}",
                'description': f"损坏的前缀: {corrupted_prefix}",
                'type': 'rule'
            })
        
        return errors

    def _generate_digit_violations(self, pattern: str) -> List[Dict]:
        """生成数字部分违规用例"""
        violations = []
        digit_part = re.search(r'\\d\{?(\d+)(?:,(\d+))?', pattern)
        
        if digit_part:
            min_len = int(digit_part.group(1))
            max_len = int(digit_part.group(2)) if digit_part.group(2) else min_len
            
            # 位数错误
            violations.extend([
                self._corrupt_digits(pattern, min_len-1, f"数字过短 ({min_len-1})"),
                self._corrupt_digits(pattern, max_len+1, f"数字过长 ({max_len+1})")
            ])
            
            # 非数字字符
            for desc, char in self.CORRUPTIONS.items():
                if desc != 'overflow':
                    violations.append(
                        self._corrupt_digits(pattern, min_len, f"非数字字符 ({desc})", char)
                    )
        
        return violations

    def _corrupt_digits(self, pattern: str, length: int, desc: str, char: str = '1') -> Dict:
        """破坏数字部分生成无效用例"""
        corrupted = re.sub(r'\\d\{?\d+,?\d*\}?', char * length, pattern[1:-1])
        return {'value': corrupted, 'description': f"规则: {desc}", 'type': 'rule'}

    def _random_digits(self, length: int) -> str:
        """生成随机数字字符串"""
        return ''.join(random.choice("0123456789") for _ in range(length))

    def _is_complex_pattern(self, pattern: str) -> bool:
        """判断是否为复杂模式"""
        return ("|" in pattern or  # 多选项模式
                "[" in pattern or  # 可选字母
                "(" in pattern or  # 分组
                pattern in ["^D[LSTP]?\\d{5}$",  # 特殊复杂模式
                        "^M[LPS]?\\d{5}$",
                        "^MT[1-3]\\d{5}$",
                        "^OP1\\d{5}$"])

    def _get_base_prefix(self, pattern: str) -> str:
        """获取基础前缀"""
        match = re.match(r'^\^([A-Za-z]+)', pattern)
        return match.group(1) if match else ""

    def _parse_digit_length(self, pattern: str) -> int:
        """解析数字长度"""
        # 处理类似OP1\d{5}这种模式
        if re.search(r'\\d\{(\d+)\}', pattern):
            match = re.search(r'\\d\{(\d+)(?:,(\d+))?\}', pattern)
            return int(match.group(1)) if match else 0
        # 处理类似1\d{5}这种模式
        elif re.search(r'\d\\d\{(\d+)\}', pattern):
            match = re.search(r'\d\\d\{(\d+)\}', pattern)
            return int(match.group(1)) + 1 if match else 0
        # 处理类似\d{5}这种模式
        else:
            match = re.search(r'\\d\{(\d+)(?:,(\d+))?\}', pattern)
            return int(match.group(1)) if match else 0


if __name__ == "__main__":
    generator = RegExpGenerator()
    all_cases = generator.generate_all_cases()
    
    for category, cases in all_cases.items():
        print(f"\n=== {category} 测试用例 ===")
        print("\n有效用例:")
        for case in cases["valid"]:
            print(f"  {case['value']:15} | {case['description']}")
        
        print("\n无效用例:")
        for case in cases["invalid"]:
            print(f"  {case['value']:15} | {case['description']}")